﻿using System.IO.Compression;
using System.Text;
using Devonline.AspNetCore;
using Devonline.Communication.Messages;
using Devonline.Core;
using Devonline.Entity;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Serilog;

var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((context, logger) => logger.ReadFrom.Configuration(context.Configuration));
builder.AddCommunicator();

var services = builder.Services;
services.AddLogging();

var app = builder.Build();
await app.StartAsync();

var logger = app.Services.GetService<ILogger<Program>>();
var communicator = app.Services.GetService<IMessageCommunicator>();
if (communicator != null && logger != null)
{
    try
    {
        Message? _message = null;
        communicator.Connected += (sender, e) =>
        {
            logger.LogWarning("通讯器已经启动");
            logger.LogInformation("输入 {type} 退出", "quit");
            logger.LogInformation("输入 {type}#{content}@{receiver} 形式将发送指定类型的消息内容给指定接收者", "消息类型", "消息内容", "接收者");
            logger.LogInformation("输入以上三种形式的两种组合, 剩余一种将采用缺省值; 仅输入一种, 则为 {type} 或 {content}, 未输入 {receiver} 将视为默认接收者", "消息类型", "消息内容", "接收者");
            logger.LogInformation("输入 {type} 将最后一条收到的消息标记为已读", "read");
            logger.LogInformation("输入 {type} 类型, 则 {content} 需要为文件的全路径", "file", "消息内容");
            logger.LogInformation("输入其余任意内容将视为文本消息内容发送给默认接收者");
        };

        communicator.Receive += async (sender, message) =>
        {
            _message = message;
            if (message.Type == MessageType.File)
            {
                var fileName = $"/home/app/dcs/file-{KeyGenerator.GetKey()}.zip";
                var data = Encoding.ASCII.GetBytes(message.Content ?? string.Empty);
                logger.LogInformation("收到了来自用户: {sender} 从: {client} 发来的文件, 内容长度: {contentLength}, 文件大小: {fileLength}, 将保存文件到默认目录: {file}", message.Sender, message.From, message.Content?.Length ?? 0, data.Length, fileName);
                await File.WriteAllBytesAsync(fileName, data);
            }
            else
            {
                logger.LogInformation("收到了来自用户: {sender} 从: {client} 发来的 {type} 类型的消息, 内容为: {content}", message.Sender, message.From, message.Type, message.Content);
            }
        };

        await communicator.StartAsync();

        var onlineMessage = await communicator.GetOnlineUsersAsync();
        if (onlineMessage is not null)
        {
            logger.LogInformation($"当前在线用户: {onlineMessage.Content}");
        }

        var input = Console.ReadLine();
        while (input != "quit")
        {
            if (!string.IsNullOrWhiteSpace(input))
            {
                try
                {
                    var array = input.Split(new char[] { AppSettings.CHAR_SHARP, AppSettings.CHAR_AT }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
                    var type = MessageType.Text;
                    string? content = null;
                    string? receiver = null;

                    //length 目前只支持 1,2,3
                    if (Enum.TryParse(array[0], true, out type))
                    {
                        if (array.Length == 3)
                        {
                            //type#?content@?receiver 形式
                            content = array[1];
                            receiver = array[2];
                        }
                        else if (array.Length == 2)
                        {
                            if (input.Contains(AppSettings.CHAR_AT))
                            {
                                //type@receiver 形式
                                receiver = array[1];
                            }
                            else
                            {
                                //type#content 形式
                                content = array[1];
                            }
                        }
                    }
                    else
                    {
                        //未指定type的情况下, 按 type = Text 处理
                        content = array[0];
                        if (array.Length >= 2 && input.Contains(AppSettings.CHAR_AT))
                        {
                            //content@receiver 形式
                            receiver = array[1];
                        }
                    }

                    switch (type)
                    {
                        //向对方发送文件
                        case MessageType.File:
                            var datetime = DateTime.Now.ToString("yyyyMMdd");
                            var fileName = content;
                            if (File.Exists(fileName))
                            {
                                try
                                {
                                    logger.LogInformation($"将发送日志文件 {fileName} 到 {receiver}!");
                                    var dir = "/data/temp/" + datetime;
                                    if (!Directory.Exists(dir))
                                    {
                                        Directory.CreateDirectory(dir);
                                    }

                                    File.Copy(fileName, $"{dir}/{Path.GetFileName(fileName)}", true);
                                    var zipFile = $"/data/temp/{datetime}.zip";
                                    if (File.Exists(zipFile))
                                    {
                                        File.Delete(zipFile);
                                    }

                                    ZipFile.CreateFromDirectory(dir, zipFile);
                                    if (File.Exists(zipFile))
                                    {
                                        var data = await File.ReadAllBytesAsync(zipFile);
                                        var buffer = Encoding.ASCII.GetString(data);
                                        logger.LogInformation($"压缩日志文件 {zipFile} 已准备就绪, 内容大小: {buffer.Length}, 文件大小: {data.Length}, 将发送到 {receiver}!");
                                        await communicator.SendAsync(buffer, MessageType.File);
                                    }

                                    Directory.Delete(dir, true);
                                }
                                catch (Exception ex)
                                {
                                    await communicator.WarningAsync("发送日志文件时出错: " + ex.GetMessage());
                                }
                            }
                            else
                            {
                                logger.LogInformation($"文件 {fileName} 不存在!");
                            }
                            break;
                        case MessageType.Read:
                            if (_message != null)
                            {
                                //消息已读形式
                                await communicator.ReadAsync(_message.Id);
                                _message = null;
                            }
                            break;
                        case MessageType.Text:
                        default:
                            //其余情况当作命令模式
                            await communicator.ExecuteAsync(type, receiver, content);
                            break;
                    }
                }
                catch (Exception ex)
                {
                    logger.LogWarning("通讯器输入处理异常: " + ex.GetMessage());
                }
            }

            input = Console.ReadLine();
        }

        await communicator.StopAsync();
    }
    catch (Exception ex)
    {
        logger.LogError(ex, "客户端链接出错, {message}", ex.GetInnerException());
    }

    await app.StopAsync();
    logger.LogInformation("客户端退出, 消息中心连接结束!");
}